package cn.jbolt.ai.core.chain.node.provider;

import cn.hutool.core.util.StrUtil;
import cn.jbolt.ai.app.config.AppConfigConstant;
import cn.jbolt.ai.app.entity.AiAppMessage;
import cn.jbolt.ai.app.service.AiAppService;
import cn.jbolt.ai.core.chain.ChainContext;
import cn.jbolt.ai.app.config.ChatNodeConfig;
import cn.jbolt.ai.app.config.FuncCallNodeConfig;
import cn.jbolt.ai.core.func.FunctionCallResult;
import cn.jbolt.ai.core.func.NativeFunctionCall;
import cn.jbolt.ai.resource.function.entity.AiFunctionResource;
import cn.jbolt.util.JSONUtil;
import cn.jbolt.util.Result;
import com.fasterxml.jackson.databind.JsonNode;
import com.jboltai.capability.message.AIMessage;
import com.jboltai.capability.model.JBoltAI;
import com.jboltai.event.Event;
import com.jboltai.event.EventErrorType;
import com.jboltai.event.ai.aifunccall.AIFuncCallEvent;
import com.jboltai.event.signal.FailEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.List;


@Component
public class FuncCallNodeProvider implements EventNodeProvider<Event> {

    private static final Logger logger = LoggerFactory.getLogger(FuncCallNodeProvider.class);
    @Autowired
    private AiAppService aiAppService;
    public Event provide(JsonNode nodeConfig, ChainContext context) {
        AIFuncCallEvent event = JBoltAI.funcCall();
        try {
            ChatNodeConfig llmConfig = ChatNodeConfig.from(nodeConfig.get(AppConfigConstant.CONFIG_TYPE_LLM));
            FuncCallNodeConfig funcCallConfig = FuncCallNodeConfig.from(nodeConfig.get(AppConfigConstant.CONFIG_TYPE_FUNCCALL));

            if (funcCallConfig.getFunctions() == null || funcCallConfig.getFunctions().length == 0) {
                if (funcCallConfig.isOutputToResponse()) {
                    context.sendErrorMsg("未绑定Function资源");
                    logger.error("FuncCallNodeProvider process 异常,异常原因: 未绑定Function资源" );

                }
                return new FailEvent("未绑定Function资源");
            }

            //根据配置初始化event
            configEvent(llmConfig, funcCallConfig, context, event);



            AiAppMessage answer;

            event.onSuccess((e, res) -> {


                if (funcCallConfig.isOutputToResponse()) {
                    //如果配置项要求 内容返回到响应里，那就输出
                    //构建相应信息
                    context.sendSuccessMsgTip("匹配到Function资源："+res.getFunction());
                    context.sendInfoMsgTip("正在执行Function,获取结果...");
                }


                Result<FunctionCallResult> result = NativeFunctionCall.call(res, event, context);
                if (result.isError()) {
                    if (funcCallConfig.isOutputToResponse()) {
                        context.sendErrorMsg("Function执行发生异常：" + result.getMsg());
                    }
                    e.fail(EventErrorType.PROGRAM_EXCEPTION, "Function执行发生异常：" + result.getMsg());
                } else {
                    context.sendSuccessMsgTip("Function执行成功");
                    if (StrUtil.isNotBlank(funcCallConfig.getResultOutputField())) {
                        //配置项要求，把结果输出到上下文
                        context.setAttr(funcCallConfig.getResultOutputField(), result.getData().getResult());
                    }
                    if (StrUtil.isNotBlank(funcCallConfig.getMatchFuncOutputField())) {
                        //配置项要求，把匹配的function输出到上下文
                        AiFunctionResource functionResource = result.getData().getFunctionResource();
                        context.setAttr(funcCallConfig.getMatchFuncOutputField(),
                                JSONUtil.createObjectNode().put("sn", functionResource.getSn()).put("description", functionResource.getBriefInfo())
                        );
                    }
                }

            });
            event.onFail((e, error) -> {
                if (funcCallConfig.isOutputToResponse()) {
                    //如果配置项要求 内容返回到响应里，那就输出
                    //构建相应信息
                    context.sendErrorMsg(error.getMsg());

                }
            });

            event.onComplete((e) -> {

            });
            return event;
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("FuncCallNodeProvider process 异常,异常原因", e);
            //context.sendErrorMsg( "网络异常,请稍后重试....");

        }
        return null;
    }

    private void configEvent(ChatNodeConfig llmConfig, FuncCallNodeConfig funcCallConfig, ChainContext context, AIFuncCallEvent event) {

        event.bindFunctionResourceByIds(funcCallConfig.getFunctions());

        String prompt = generatePrompt(llmConfig, context);
        event.prompt(prompt);
        if (llmConfig.getModelType() != null) {
            event.setModel(llmConfig.getModelType());
        }
        if (StrUtil.isNotBlank(llmConfig.getDefaultModel())) {
            event.setModelName(llmConfig.getDefaultModel());
        }
        if (llmConfig.getMaxTokens() > 0) {
            event.setMaxTokens(llmConfig.getMaxTokens());
        }
        if (StrUtil.isNotBlank(llmConfig.getSystemRole())) {
            event.systemMessage(llmConfig.getSystemRole());
        }
        if (llmConfig.isUseContext()) {
            Long appId = context.getAiApp().getId();
            Long sessionId = context.getAiSession().getId();
            List<AIMessage> messageList = aiAppService.getAppSessionContextMessages(sessionId, appId);
            if (messageList != null && messageList.size() > 0) {
                event.contextMessages(messageList);
            }
        }
        if (llmConfig.getTemperature() != null ) {
            event.setTemperature(llmConfig.getTemperature());
        }
        if (llmConfig.getTopP() != null && llmConfig.getTopP()>0) {
            event.setTopP(llmConfig.getTopP());
        }
        if (llmConfig.getTopK() != null && llmConfig.getTopK()>0) {
            event.setTopK(llmConfig.getTopK());
        }

    }

    /**
     * 生成提示词
     *
     * @param config  配置
     * @param context 上下文
     * @return 处理后的提示词
     */
    private String generatePrompt(ChatNodeConfig config, ChainContext context) {
        if (StrUtil.isBlank(config.getPromptTpl())) {
            return context.getOriPrompt();
        }

        String template = config.getPromptTpl();
        if (context.getArgs() == null || context.getArgs().isEmpty()) {
            return template;
        }

        for (String key : context.getArgs().keySet()) {
            Object value = context.getArgs().get(key);
            if (value != null) {
                // 处理可能存在的空格情况，如 ${ key } 或 ${key}
                template = template.replaceAll("\\$\\{\\s*" + key + "\\s*\\}", value.toString());
            }
        }

        return template;
    }


}
